/*
 * SecurityServiceFactory.java
 *
 * Created on 14 luty 2007, 21:58
 *
 */

package arocms.security;

import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import org.apache.log4j.Logger;

/**
 *
 * @author arek
 */
public class SecurityServiceFactory {
    
    private static SecurityService sservice;

    private static Logger log = Logger.getLogger(SecurityServiceFactory.class);
    
    /** Creates a new instance of SecurityServiceFactory */
    public SecurityServiceFactory() {
    }
   
    public static SecurityService configure() throws SecurityServiceConfigurationException{
        return configure("arocms.cfg.xml");
    }
    
    public static SecurityService configure(String resourceName) throws SecurityServiceConfigurationException{
        try {
            if (sservice!=null) return sservice;
            log.info("Opening " + resourceName + ".");
            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( resourceName );    //Open a configuration xml file for reading
            log.info("Parsing configuration.");
            Document xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( is );                   //Create an XML Document
            XPath path = XPathFactory.newInstance().newXPath();                                                     //Create an XPath to navigate through configuration document
            log.info("Reading class name implementing SecurityService.");
            String className = (String) path.evaluate("/arocms-configuration/security-service/@class", xml);        //Read a class name of a service.
            log.debug("Class name is: " + className);
            sservice = (SecurityService) Class.forName( className ).newInstance();                                  //Create a new instance of the service.
            log.info("Reading parameters.");
            int paramCount = ((Number) path.evaluate("count(/arocms-configuration/security-service/parameter)", xml, XPathConstants.NUMBER)).intValue(); //Count parameters
            log.debug("There is " + paramCount + " parameters.");
            String parameterName;
            String parameterValue;
            for (int i=1; i<= paramCount; i++) {
                parameterName = (String) path.evaluate("/arocms-configuration/security-service/parameter["+i+"]/@name", xml);   //Read parameter name
                parameterValue = (String) path.evaluate("/arocms-configuration/security-service/parameter["+i+"]/@value", xml); //Read parameter value
                log.debug("parameter: name=" + parameterName + " value=" + parameterValue);
                sservice.getClass().getDeclaredField(parameterName).set(sservice, parameterValue);                  //Sets a field value of implementing class corresponding to parameterName and parameterValue
            }
            sservice.configure();
        } catch (Exception ex) {
            log.fatal("Can not finalize setting up security service.");
            sservice = null;                                                                                        //In case of any error, sservice becomes uninitialized.
            SecurityServiceConfigurationException ex2 = new SecurityServiceConfigurationException();
            ex2.setStackTrace(ex.getStackTrace());
            throw ex2;                                                                                              //Rethrow an exception.
        }
        log.info("Security Service initialized successfully.");
        return sservice;                                                                                            //or return sservice (for method chaining)
    }
}
